/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.servlet.handler;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.MethodIntrospector;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerMapping;

/**
 * Abstract base class for {@link HandlerMapping} implementations that define
 * a mapping between a request and a {@link HandlerMethod}.
 *
 * <p>For each registered handler method, a unique mapping is maintained with
 * subclasses defining the details of the mapping type {@code <T>}.
 *
 * @author Arjen Poutsma
 * @author Rossen Stoyanchev
 * @author Juergen Hoeller
 * @since 3.1
 * @param <T> The mapping for a {@link HandlerMethod} containing the conditions
 * needed to match the handler method to incoming request.
 */
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {

	/**
	 * Bean name prefix for target beans behind scoped proxies. Used to exclude those
	 * targets from handler method detection, in favor of the corresponding proxies.
	 * <p>We're not checking the autowire-candidate status here, which is how the
	 * proxy target filtering problem is being handled at the autowiring level,
	 * since autowire-candidate may have been turned to {@code false} for other
	 * reasons, while still expecting the bean to be eligible for handler methods.
	 * <p>Originally defined in {@link org.springframework.aop.scope.ScopedProxyUtils}
	 * but duplicated here to avoid a hard dependency on the spring-aop module.
	 */
	private static final String SCOPED_TARGET_NAME_PREFIX = "scopedTarget.";

	private static final HandlerMethod PREFLIGHT_AMBIGUOUS_MATCH =
			new HandlerMethod(new EmptyHandler(), ClassUtils.getMethod(EmptyHandler.class, "handle"));

	private static final CorsConfiguration ALLOW_CORS_CONFIG = new CorsConfiguration();

	static {
		ALLOW_CORS_CONFIG.addAllowedOrigin("*");
		ALLOW_CORS_CONFIG.addAllowedMethod("*");
		ALLOW_CORS_CONFIG.addAllowedHeader("*");
		ALLOW_CORS_CONFIG.setAllowCredentials(true);
	}


	private boolean detectHandlerMethodsInAncestorContexts = false;

	private HandlerMethodMappingNamingStrategy<T> namingStrategy;

	private final MappingRegistry mappingRegistry = new MappingRegistry();


	/**
	 * Whether to detect handler methods in beans in ancestor ApplicationContexts.
	 * <p>Default is "false": Only beans in the current ApplicationContext are
	 * considered, i.e. only in the context that this HandlerMapping itself
	 * is defined in (typically the current DispatcherServlet's context).
	 * <p>Switch this flag on to detect handler beans in ancestor contexts
	 * (typically the Spring root WebApplicationContext) as well.
	 */
	public void setDetectHandlerMethodsInAncestorContexts(boolean detectHandlerMethodsInAncestorContexts) {
		this.detectHandlerMethodsInAncestorContexts = detectHandlerMethodsInAncestorContexts;
	}

	/**
	 * Configure the naming strategy to use for assigning a default name to every
	 * mapped handler method.
	 * <p>The default naming strategy is based on the capital letters of the
	 * class name followed by "#" and then the method name, e.g. "TC#getFoo"
	 * for a class named TestController with method getFoo.
	 */
	public void setHandlerMethodMappingNamingStrategy(HandlerMethodMappingNamingStrategy<T> namingStrategy) {
		this.namingStrategy = namingStrategy;
	}

	/**
	 * Return the configured naming strategy or {@code null}.
	 */
	public HandlerMethodMappingNamingStrategy<T> getNamingStrategy() {
		return this.namingStrategy;
	}

	/**
	 * Return a (read-only) map with all mappings and HandlerMethod's.
	 */
	public Map<T, HandlerMethod> getHandlerMethods() {
		this.mappingRegistry.acquireReadLock();
		try {
			return Collections.unmodifiableMap(this.mappingRegistry.getMappings());
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}

	/**
	 * Return the handler methods for the given mapping name.
	 * @param mappingName the mapping name
	 * @return a list of matching HandlerMethod's or {@code null}; the returned
	 * list will never be modified and is safe to iterate.
	 * @see #setHandlerMethodMappingNamingStrategy
	 */
	public List<HandlerMethod> getHandlerMethodsForMappingName(String mappingName) {
		return this.mappingRegistry.getHandlerMethodsByMappingName(mappingName);
	}

	/**
	 * Return the internal mapping registry. Provided for testing purposes.
	 */
	MappingRegistry getMappingRegistry() {
		return this.mappingRegistry;
	}

	/**
	 * Register the given mapping.
	 * <p>This method may be invoked at runtime after initialization has completed.
	 * @param mapping the mapping for the handler method
	 * @param handler the handler
	 * @param method the method
	 */
	public void registerMapping(T mapping, Object handler, Method method) {
		this.mappingRegistry.register(mapping, handler, method);
	}

	/**
	 * Un-register the given mapping.
	 * <p>This method may be invoked at runtime after initialization has completed.
	 * @param mapping the mapping to unregister
	 */
	public void unregisterMapping(T mapping) {
		this.mappingRegistry.unregister(mapping);
	}


	// Handler method detection

	/**
	 * Detects handler methods at initialization.
	 */
	@Override
	public void afterPropertiesSet() {
		initHandlerMethods();
	}

	/**注册处理器方法
	 * <br/>Scan beans in the ApplicationContext, detect and register handler methods.
	 * @see #isHandler(Class)
	 * @see #getMappingForMethod(Method, Class)
	 * @see #handlerMethodsInitialized(Map)
	 */
	protected void initHandlerMethods() {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for request mappings in application context: " + getApplicationContext());
		}
		String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		for (String beanName : beanNames) {
			// 排除scoped目标类型bean，scoped目标类型bean是一种特殊的bean，带有一些特殊的作用域代理，这种bean不能作为处理器bean使用，故直接忽略
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				Class<?> beanType = null;
				try {
					beanType = getApplicationContext().getType(beanName);
				}
				catch (Throwable ex) {
					// 无法解析beanType时抛出异常，可能该beanName对应的bean是懒加载的，此时直接忽略，仅打印日志
					if (logger.isDebugEnabled()) {
						logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
					}
				}
				// 如果获取到的bean类型不为空，且通过isHandler方法判断是一个处理器类型的bean
				if (beanType != null && isHandler(beanType)) {
					// 则执行检测处理器方法的逻辑
					detectHandlerMethods(beanName);
				}
			}
		}
		// 在全部处理器方法检测完成后，执行处理器方法初始化完成的处理方法，把全部处理器方法作为参数传入，用于执行一些统一的逻辑。默认实现中未作任何操作
		handlerMethodsInitialized(getHandlerMethods());
	}

	/**从处理器中查找处理器方法
	 * <br/>Look for handler methods in a handler.
	 * @param handler the bean name of a handler or a handler instance
	 */
	protected void detectHandlerMethods(final Object handler) {
		// 如果传入的handler为String类型，则表示一个beanName，尝试从应用上下文中获取该beanName对应的beanType作为处理器类型handlerType，否则直接取handler的Class为handlerType
		Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());
		// 获取该处理器类型对应的用户定义类型，该逻辑内部判断处理器类型是否是代理类型，如果是自动生成的动态代理类型，则获取该代理的原始类型，则用户定义的类型
		final Class<?> userType = ClassUtils.getUserClass(handlerType);

		// 通过工具类MethodIntrospector的selectMethods，遍历处理器类型上的全部方法，
		// 为每个方法执行getMappingForMethod逻辑获取映射信息，返回Map类型，key为方法，value是方法对应的映射信息
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				new MethodIntrospector.MetadataLookup<T>() {
					@Override
					public T inspect(Method method) {
						try {
							// 执行getMappingForMethod方法，获取当前遍历中方法对应的映射信息，该方法可以返回null，如果返回null，该method不会被添加到结果methods中
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex);
						}
					}
				});

		if (logger.isDebugEnabled()) {
			logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
		}
		// 遍历上述methods结果，为其中的方法与方法对应的映射信息执行注册处理器方法逻辑
		for (Map.Entry<Method, T> entry : methods.entrySet()) {
			// 获取真实的可执行方法，因为上述查找逻辑在特殊情况下查找到的方法可能存在于代理上，需要获取非代理方法作为可执行方法调用
			Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
			T mapping = entry.getValue();
			// 传入处理器(当前为处理器beanName)、可调用方法与映射信息，注册处理器方法
			registerHandlerMethod(handler, invocableMethod, mapping);
		}
	}

	/**注册一个处理程序方法及其唯一的映射
	 * <br/>Register a handler method and its unique mapping. Invoked at startup for each detected handler method.
	 * @param handler the bean name of the handler or the handler instance
	 * @param method the method to register
	 * @param mapping the mapping conditions associated with the handler method
	 * @throws IllegalStateException if another method was already registered
	 * under the same mapping
	 */
	protected void registerHandlerMethod(Object handler, Method method, T mapping) {
		this.mappingRegistry.register(mapping, handler, method);
	}

	/**获取处理器方法实例，处理器方法中封装了处理器实例，以及处理器类型中的方法，调用处理器方法时通过反射调用处理器实例的method方法
	 * <br/>Create the HandlerMethod instance.
	 * @param handler either a bean name or an actual handler instance
	 * @param method the target method
	 * @return the created HandlerMethod
	 */
	protected HandlerMethod createHandlerMethod(Object handler, Method method) {
		HandlerMethod handlerMethod;
		// 如果传入的处理器是string类型，则视为一个beanName
		if (handler instanceof String) {
			String beanName = (String) handler;
			// 创建处理器方法实例，封装beanName、beanFactory实例与原始方法
			handlerMethod = new HandlerMethod(beanName, getApplicationContext().getAutowireCapableBeanFactory(), method);
			// 在getHandlerInternal逻辑中，最后执行了处理器方法实例的createWithResolvedBean，就是为了把上面封装的beanName通过beanFactory解析为对应的处理器bean实例
			// 这里没有立即获取beanName对应的bean实例是为了实现延迟加载的目的
		}
		else {
			// 否则直接封装为处理器方法
			handlerMethod = new HandlerMethod(handler, method);
		}
		return handlerMethod;
	}

	/**
	 * Extract and return the CORS configuration for the mapping.
	 */
	protected CorsConfiguration initCorsConfiguration(Object handler, Method method, T mapping) {
		return null;
	}

	/**
	 * Invoked after all handler methods have been detected.
	 * @param handlerMethods a read-only map with handler methods and mappings.
	 */
	protected void handlerMethodsInitialized(Map<T, HandlerMethod> handlerMethods) {
	}

	/**首先会获取当前request的uri，然后通过uri查找HandlerMethod，并且在最后，会判断获取到的HandlerMethod中的bean是否为String类型的，如果是，则在当前BeanFactory中查找该名称的bean，并且将其封装为HandlerMethod对象
	 * <br/>Look up a handler method for the given request.
	 */
	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		// 获取当前request的URI，作为查找路径
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		if (logger.isDebugEnabled()) {
			logger.debug("Looking up handler method for path " + lookupPath);
		}
		// 获取注册的Mapping的读锁，有了此加锁功能，可以实现在项目运行期间，使用一些线程动态的向映射注册器中注册映射信息，也不影响正在从映射注册器中获取映射数据的线程
		this.mappingRegistry.acquireReadLock();
		try {
			// 通过path和request查找具体的HandlerMethod
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			if (logger.isDebugEnabled()) {
				if (handlerMethod != null) {
					logger.debug("Returning handler method [" + handlerMethod + "]");
				}
				else {
					logger.debug("Did not find handler method for [" + lookupPath + "]");
				}
			}
			// 返回处理器方法，如果处理器方法不为空，则判断其bean属性是否是String类型，是则在BeanFactory中查找该bean，并将其封装为一个HandlerMethod对象
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			// 释放当前注册的Mapping的读锁
			this.mappingRegistry.releaseReadLock();
		}
	}

	/**首先会通过uri进行直接匹配，如果能匹配到，则在匹配结果中尝试进行RequestMethod，Consumes和Produces等配置的匹配；如果通过uri不能匹配到，则直接对所有定义的RequestMapping进行匹配，这里主要是进行正则匹配。
	 * <br/>如果能够匹配到，则对匹配结果按照相似度进行排序，并且对前两个结果相似度进行比较，如果相似度一样，则抛出异常，如果不一样，则返回相似度最高的一个匹配结果。如果无法获取到匹配结果，则对所有的匹配结果进行遍历，
	 * <br/>判断当前request具体是哪一部分参数无法匹配到结果。对于匹配结果的获取，主要在addMatchingMappings()方法中
	 * Look up the best-matching handler method for the current request.
	 * If multiple matches are found, the best match is selected.
	 * @param lookupPath mapping lookup path within the current servlet mapping
	 * @param request the current request
	 * @return the best-matching handler method, or {@code null} if no match
	 * @see #handleMatch(Object, String, HttpServletRequest)
	 * @see #handleNoMatch(Set, String, HttpServletRequest)
	 */
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		// 创建匹配结果列表，用于保存多个匹配结果，Match为匹配的映射信息与处理器方法的封装
		List<Match> matches = new ArrayList<Match>();
		// 首先尝试通过映射注册器的getMappingsByUrl方法获取请求路径直接对应的映射信息列表，通过这种方式达到优化查找处理器方法速度的目的。这种优化主要针对@RequestMapping中的path属性直接指定了具体路径的情况，
		// 可通过路径直接获取该映射信息，达到快速获取匹配结果的目的。如果不能直接获取匹配的映射信息，则需要遍历注册到映射注册器中的全部映射信息，才能获取匹配结果
		// 还要注意，这里获取到的是映射列表，但是具体哪些RequestMappingInfo是匹配的，还需要根据RequestMappingInfo注解的条件进一步过滤
		// 如果请求地址是/test，就可以直接获取到directPathMatches: [{[/test],methods=[GET]}]
		// 如果请求地址是/test/123，则directPathMatches: null
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		if (directPathMatches != null) {
			// 如果请求地址是/test，处理完之后matches: [{[/test],methods=[GET]}]
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
			// 如果请求地址是/test/123，处理完之后matches: [{[/test/{id}],methods=[GET]}]
			// 如果无法通过uri进行直接匹配，则对所有的注册的RequestMapping进行匹配，这里无法通过uri匹配的情况主要有三种：
	        // ①在RequestMapping中定义的是PathVariable，如/user/detail/{id}；
	        // ②在RequestMapping中定义了问号表达式，如/user/?etail；
	        // ③在RequestMapping中定义了*或**匹配，如/user/detail/**
			addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
		}

		if (!matches.isEmpty()) {
			// 对匹配的结果进行排序，获取相似度最高的一个作为结果返回，这里对相似度的判断是，
			// 会判断前两个是否相似度是一样的，如果是一样的，则直接抛出异常，如果不相同，则直接返回最高的一个
			Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
			Collections.sort(matches, comparator);
			if (logger.isTraceEnabled()) {
				logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
			}
			// 获取匹配程度最高的一个匹配结果
			Match bestMatch = matches.get(0);
			if (matches.size() > 1) {
				// 如果匹配结果不止一个，首先会判断是否是跨域请求，如果是，则返回一个预先定义好的处理器方法：PREFLIGHT_AMBIGUOUS_MATCH，如果不是，则会判断前两个匹配程度是否相同，如果相同则抛出异常
				if (CorsUtils.isPreFlightRequest(request)) {
					return PREFLIGHT_AMBIGUOUS_MATCH;
				}
				Match secondBestMatch = matches.get(1);
				if (comparator.compare(bestMatch, secondBestMatch) == 0) {
					Method m1 = bestMatch.handlerMethod.getMethod();
					Method m2 = secondBestMatch.handlerMethod.getMethod();
					throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
				}
			}
			request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
			// 主要对匹配的映射信息结果进行统一处理，并把匹配结果解析后添加到请求属性中，以供后续的逻辑可以根据匹配结果获取一些信息。如参数绑定时，@PathVariable需要从匹配的路径变量中获取信息，返回值处理时响应的内容类型又可以根据匹配的produces条件进行自动处理
			handleMatch(bestMatch.mapping, lookupPath, request);
			return bestMatch.handlerMethod;
		}
		else {
			// 如果匹配结果是空的，则对所有注册的Mapping进行遍历，判断当前request具体是哪种情况导致的无法匹配：
			// ①RequestMethod无法匹配；
			// ②Consumes无法匹配；
			// ③Produces无法匹配；
			// ④Params无法匹配
			return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
		}
	}

	/**对于RequestMapping的匹配，这里逻辑比较简单，就是对所有的RequestMappingInfo进行遍历，然后将request分别于每个RequestMappingInfo进行匹配，如果匹配上了，其返回值就不为空，最后将所有的匹配结果封装为Match返回
	 * @param mappings
	 * @param matches
	 * @param request
	 */
	private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
		for (T mapping : mappings) {
			// 尝试获取匹配的映射信息
			T match = getMatchingMapping(mapping, request);
			if (match != null) {
				// 如果匹配结果不为空，则封装为Match对象，添加到匹配结果列表中
				// 构造Match的第二个参数是处理器方法，需要通过映射注册器根据当前遍历中的映射获取
				matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
			}
		}
	}

	/**
	 * Invoked when a matching mapping is found.
	 * @param mapping the matching mapping
	 * @param lookupPath mapping lookup path within the current servlet mapping
	 * @param request the current request
	 */
	protected void handleMatch(T mapping, String lookupPath, HttpServletRequest request) {
		// 仅是向请求中添加当前的查找路径属性，用在后续来处理逻辑
		request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath);
	}

	/**
	 * Invoked when no matching mapping is not found.
	 * @param mappings all registered mappings
	 * @param lookupPath mapping lookup path within the current servlet mapping
	 * @param request the current request
	 * @throws ServletException in case of errors
	 */
	protected HandlerMethod handleNoMatch(Set<T> mappings, String lookupPath, HttpServletRequest request)
			throws Exception {

		return null;
	}

	@Override
	protected CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {
		CorsConfiguration corsConfig = super.getCorsConfiguration(handler, request);
		if (handler instanceof HandlerMethod) {
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			if (handlerMethod.equals(PREFLIGHT_AMBIGUOUS_MATCH)) {
				return AbstractHandlerMethodMapping.ALLOW_CORS_CONFIG;
			}
			else {
				CorsConfiguration corsConfigFromMethod = this.mappingRegistry.getCorsConfiguration(handlerMethod);
				corsConfig = (corsConfig != null ? corsConfig.combine(corsConfigFromMethod) : corsConfigFromMethod);
			}
		}
		return corsConfig;
	}


	// Abstract template methods

	/**
	 * Whether the given type is a handler with handler methods.
	 * @param beanType the type of the bean being checked
	 * @return "true" if this a handler type, "false" otherwise.
	 */
	protected abstract boolean isHandler(Class<?> beanType);

	/**
	 * Provide the mapping for a handler method. A method for which no
	 * mapping can be provided is not a handler method.
	 * @param method the method to provide a mapping for
	 * @param handlerType the handler type, possibly a sub-type of the method's
	 * declaring class
	 * @return the mapping, or {@code null} if the method is not mapped
	 */
	protected abstract T getMappingForMethod(Method method, Class<?> handlerType);

	/**
	 * Extract and return the URL paths contained in a mapping.
	 */
	protected abstract Set<String> getMappingPathPatterns(T mapping);

	/**
	 * Check if a mapping matches the current request and return a (potentially
	 * new) mapping with conditions relevant to the current request.
	 * @param mapping the mapping to get a match for
	 * @param request the current HTTP servlet request
	 * @return the match, or {@code null} if the mapping doesn't match
	 */
	protected abstract T getMatchingMapping(T mapping, HttpServletRequest request);

	/**
	 * Return a comparator for sorting matching mappings.
	 * The returned comparator should sort 'better' matches higher.
	 * @param request the current request
	 * @return the comparator (never {@code null})
	 */
	protected abstract Comparator<T> getMappingComparator(HttpServletRequest request);


	/**映射注册器
	 * <br/>A registry that maintains all mappings to handler methods, exposing methods to perform lookups and providing concurrent access.
	 * <p>Package-private for testing purposes.
	 */
	class MappingRegistry {

		/**映射注册表，用于保存映射注册信息的Map，key是映射信息，value是该映射信息对应的全部注册信息的封装MappingRegistration
		 * <br/>注意，MappingRegistration中的4个信息正好是下面4个map中的key
		 */
		private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>();

		/**映射查找表，用于保存全部映射信息与对应的处理器方法的Map，通过getMappings方法直接暴露该查找表
		 */
		private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>();

		/**url查找表(直接路径查找表)，用于保存直接路径对应的映射信息列表，优化直接路径的处理器查找效率，key是直接路径，value是映射信息的列表
		 * <br/>通过getMappingsByUrl方法向外提供根据直接路径获取对应的映射信息列表功能
		 */
		private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();

		/**name查找表(映射名查找表)，用于保存映射名对应的处理器方法列表。用于辅助支持功能，根据映射名获取处理器方法，再根据处理器方法构造url的路径信息与参数信息。
		 * <br/>通过getHandlerMethodsByMappingName方法向外提供根据映射名获取对应处理器方法列表功能
		 */
		private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<String, List<HandlerMethod>>();

		/**CORS查找表(跨域配置查找表)，用于保存处理器方法对应的CORS跨域配置，暂不考虑
		 */
		private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<HandlerMethod, CorsConfiguration>();

		/**可重入读写锁，用于保证映射注册器的线程安全性
		 */
		private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

		/**获取全部映射信息map
		 * <br/>Return all mappings and handler methods. Not thread-safe.
		 * @see #acquireReadLock()
		 */
		public Map<T, HandlerMethod> getMappings() {
			return this.mappingLookup;
		}

		/**根据路径获取映射信息列表
		 * <br/>Return matches for the given URL path. Not thread-safe.
		 * @see #acquireReadLock()
		 */
		public List<T> getMappingsByUrl(String urlPath) {
			// 通过保存路径与映射信息列表关系的map: urlLookup直接获取路径对应的映射信息列表
			return this.urlLookup.get(urlPath);
		}

		/**
		 * Return handler methods by mapping name. Thread-safe for concurrent use.
		 */
		public List<HandlerMethod> getHandlerMethodsByMappingName(String mappingName) {
			return this.nameLookup.get(mappingName);
		}

		/**
		 * Return CORS configuration. Thread-safe for concurrent use.
		 */
		public CorsConfiguration getCorsConfiguration(HandlerMethod handlerMethod) {
			HandlerMethod original = handlerMethod.getResolvedFromHandlerMethod();
			return this.corsLookup.get(original != null ? original : handlerMethod);
		}

		/**
		 * Acquire the read lock when using getMappings and getMappingsByUrl.
		 */
		public void acquireReadLock() {
			this.readWriteLock.readLock().lock();
		}

		/**
		 * Release the read lock after using getMappings and getMappingsByUrl.
		 */
		public void releaseReadLock() {
			this.readWriteLock.readLock().unlock();
		}

		/**注册映射信息
		 * @param mapping 映射信息封装
		 * @param handler 处理器，一般为一个bean实例或beanName，用于作为实例调用处理器方法
		 * @param method 映射信息对应的处理器实例中的原始方法，未封装为HandlerMethod对象
		 */
		public void register(T mapping, Object handler, Method method) {
			// 注册前先获取写锁
			this.readWriteLock.writeLock().lock();
			try {
				// 把处理器与原始方法封装为处理器方法
				HandlerMethod handlerMethod = createHandlerMethod(handler, method);
				// 判断该处理器方法是否唯一，防止相同的映射信息对应多个不同的处理器方法，导致查找处理器方法时无法找到唯一最优匹配
				assertUniqueMethodMapping(handlerMethod, mapping);

				if (logger.isInfoEnabled()) {
					logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
				}
				// 向映射查找表中添加当前映射信息与对应的处理器方法
				this.mappingLookup.put(mapping, handlerMethod);

				// 获取当前注册的映射信息包含的直接路径列表
				List<String> directUrls = getDirectUrls(mapping);
				for (String url : directUrls) {
					this.urlLookup.add(url, mapping);
				}

				String name = null;
				// 如果命名策略不为空
				if (getNamingStrategy() != null) {
					// 通过命名策略获取映射名
					// 对于@RequestMapping的处理器映射类RequestMappingHandlerMapping来说，在其父类RequestMappingInfoHandlerMapping中，默认注册RequestMappingInfoHandlerMethodMappingNamingStrategy命名策略，
					// 该策略首先使用@RequestMapping注解提供的name属性值作为映射名，当name为空时，使用处理器方法中处理器类型名的大写字母拼接#后再拼接处理器方法名作为映射名使用
					// 例如处理器类名为MyController，标记@RequestMapping的方法为myMapping，且未提供name属性，则处理器名为MC#myMapping
					name = getNamingStrategy().getName(handlerMethod, mapping);
					// 向name查找表中添加映射名对应的处理器方法
					addMappingName(name, handlerMethod);
				}

				// 获取处理器方法对应的CORS配置
				CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
				if (corsConfig != null) {
					// 如果配置不为空，则添加到CORS查找表中
					this.corsLookup.put(handlerMethod, corsConfig);
				}

				// 把上述全部查找表中的key作为注册信息封装为MappingRegistration，添加到注册表中
				// 该registry的作用就是为了实现映射的注销操作，用以在注销映射时，同时注销几个查找表中的数据，防止内存泄露，见unregister
				this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
			}
			finally {
				// 解锁
				this.readWriteLock.writeLock().unlock();
			}
		}

		private void assertUniqueMethodMapping(HandlerMethod newHandlerMethod, T mapping) {
			// 先根据映射信息获取当前已经注册到映射查询表中的处理器方法
			// 在映射信息中的全部属性均相同时，两个映射信息视为相同，即只有@RequestMapping注解中属性完全相同时，两个注解视为相同，使用这两个注解生成的映射信息在映射查找表中视为相同的key
			HandlerMethod handlerMethod = this.mappingLookup.get(mapping);
			if (handlerMethod != null && !handlerMethod.equals(newHandlerMethod)) {
				// 如果原处理器方法不为空，且当前新注册的处理器方法与原处理器方法不是同一个，则抛出异常，异常中包含了相关信息
				throw new IllegalStateException(
						"Ambiguous mapping. Cannot map '" +	newHandlerMethod.getBean() + "' method \n" +
						newHandlerMethod + "\nto " + mapping + ": There is already '" +
						handlerMethod.getBean() + "' bean method\n" + handlerMethod + " mapped.");
			}
		}

		/**获取映射信息对应的直接路径列表
		 * @param mapping
		 * @return
		 */
		private List<String> getDirectUrls(T mapping) {
			List<String> urls = new ArrayList<String>(1);
			// 通过调用抽象方法getMappingPathPatterns获取该映射信息中的全部路径模式，并进行遍历
			// getMappingPathPatterns的实现对于@RequestMapping注解对应的处理器映射RequestMappingHandlerMapping，该方法的实现是在其父类RequestMappingInfoHandlerMapping中，其逻辑为获取@RequestMapping注解中path属性的值
			for (String path : getMappingPathPatterns(mapping)) {
				// 如果路径是模式串，则跳过，只添加非模式串的路径，即直接路径
				if (!getPathMatcher().isPattern(path)) {
					urls.add(path);
				}
			}
			return urls;
		}

		/**添加映射名，一个映射名对应一个处理器方法列表
		 * @param name 映射名
		 * @param handlerMethod 为该映射名添加的处理器方法
		 */
		private void addMappingName(String name, HandlerMethod handlerMethod) {
			// 先获取当前映射名对应的处理器列表
			List<HandlerMethod> oldList = this.nameLookup.get(name);
			if (oldList == null) {
				oldList = Collections.<HandlerMethod>emptyList();
			}

			// 如果在原处理器方法列表中包含当前处理器方法，则直接返回
			for (HandlerMethod current : oldList) {
				if (handlerMethod.equals(current)) {
					return;
				}
			}

			if (logger.isTraceEnabled()) {
				logger.trace("Mapping name '" + name + "'");
			}

			// 创建新的处理器方法列表
			List<HandlerMethod> newList = new ArrayList<HandlerMethod>(oldList.size() + 1);
			// 合并原处理器方法列表与当前的处理器方法
			newList.addAll(oldList);
			newList.add(handlerMethod);
			// 再放入name查找表
			this.nameLookup.put(name, newList);

			if (newList.size() > 1) {
				if (logger.isTraceEnabled()) {
					logger.trace("Mapping name clash for handlerMethods " + newList + ". Consider assigning explicit names.");
				}
			}
		}

		/**注销mapping映射，包括该映射的所有注册信息
		 * @param mapping
		 */
		public void unregister(T mapping) {
			// 同注册，需要加写锁，以支持运行期动态注销
			this.readWriteLock.writeLock().lock();
			try {
				// 移除该映射在注册表中对应的注册信息，同时获取移除的注册信息
				MappingRegistration<T> definition = this.registry.remove(mapping);
				if (definition == null) {
					return;
				}

				// 通过注册信息中的映射信息移除映射查找表数据
				this.mappingLookup.remove(definition.getMapping());

				// 遍历注册信息中的直接路径
				for (String url : definition.getDirectUrls()) {
					// 获取直接路径对应的url查找表中的映射信息列表
					List<T> list = this.urlLookup.get(url);
					if (list != null) {
						list.remove(definition.getMapping());
						if (list.isEmpty()) {
							this.urlLookup.remove(url);
						}
					}
				}

				// 移除name查找表中当前映射信息相关数据，与注册逻辑相反
				removeMappingName(definition);
				// 从CORS查找表中移除当前映射信息对应的数据
				this.corsLookup.remove(definition.getHandlerMethod());
			}
			finally {
				this.readWriteLock.writeLock().unlock();
			}
		}

		private void removeMappingName(MappingRegistration<T> definition) {
			String name = definition.getMappingName();
			if (name == null) {
				return;
			}
			HandlerMethod handlerMethod = definition.getHandlerMethod();
			List<HandlerMethod> oldList = this.nameLookup.get(name);
			if (oldList == null) {
				return;
			}
			if (oldList.size() <= 1) {
				this.nameLookup.remove(name);
				return;
			}
			List<HandlerMethod> newList = new ArrayList<HandlerMethod>(oldList.size() - 1);
			for (HandlerMethod current : oldList) {
				if (!current.equals(handlerMethod)) {
					newList.add(current);
				}
			}
			this.nameLookup.put(name, newList);
		}
	}


	/**映射信息对应的全部注册信息的封装
	 * @author zhangsulei
	 * @param <T>
	 */
	private static class MappingRegistration<T> {

		/**映射信息
		 */
		private final T mapping;

		/**对应的处理器方法
		 */
		private final HandlerMethod handlerMethod;

		/**映射信息中的直接路径(非模式化路径)
		 */
		private final List<String> directUrls;

		/**映射名
		 */
		private final String mappingName;

		public MappingRegistration(T mapping, HandlerMethod handlerMethod, List<String> directUrls, String mappingName) {
			Assert.notNull(mapping, "Mapping must not be null");
			Assert.notNull(handlerMethod, "HandlerMethod must not be null");
			this.mapping = mapping;
			this.handlerMethod = handlerMethod;
			this.directUrls = (directUrls != null ? directUrls : Collections.<String>emptyList());
			this.mappingName = mappingName;
		}

		public T getMapping() {
			return this.mapping;
		}

		public HandlerMethod getHandlerMethod() {
			return this.handlerMethod;
		}

		public List<String> getDirectUrls() {
			return this.directUrls;
		}

		public String getMappingName() {
			return this.mappingName;
		}
	}


	/**
	 * A thin wrapper around a matched HandlerMethod and its mapping, for the purpose of
	 * comparing the best match with a comparator in the context of the current request.
	 */
	private class Match {

		private final T mapping;

		private final HandlerMethod handlerMethod;

		public Match(T mapping, HandlerMethod handlerMethod) {
			this.mapping = mapping;
			this.handlerMethod = handlerMethod;
		}

		@Override
		public String toString() {
			return this.mapping.toString();
		}
	}


	private class MatchComparator implements Comparator<Match> {

		private final Comparator<T> comparator;

		public MatchComparator(Comparator<T> comparator) {
			this.comparator = comparator;
		}

		@Override
		public int compare(Match match1, Match match2) {
			return this.comparator.compare(match1.mapping, match2.mapping);
		}
	}


	private static class EmptyHandler {

		public void handle() {
			throw new UnsupportedOperationException("Not implemented");
		}
	}

}
